package com.yunkai.plate_lpr;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import android.util.Log;
import android.util.Range;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class CameraUtil {
  private Semaphore mCameraOpenCloseLock = new Semaphore(1);// 以防止在关闭相机之前应用程序退出
  private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
  static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
  }

//  private CraREActivity activity;
  private WeakReference<CraREActivity> activityRef; // 替换原有的 activity 字段
  private static final String TAG = "OpenCV/";
  private AutoFitTextureView textureView;// 视图
  private ImageView imageView;

  // 摄像头ID（通常0代表后置摄像头，1代表前置摄像头）
  private String mCameraId = "0";
  // 定义代表摄像头的成员变量
  private CameraDevice cameraDevice;
  // 预览尺寸
  private Size previewSize;
  private CaptureRequest.Builder previewRequestBuilder;
  // 定义用于预览照片的捕获请求
  private CaptureRequest previewRequest;
  // 定义CameraCaptureSession成员变量
  private CameraCaptureSession captureSession;

  private boolean isprv;
  private TextureView.SurfaceTextureListener mSurfaceTextureListener;
  private CameraDevice.StateCallback stateCallback;
  private CameraManager manager;
  private Surface surface;
  private Range<Integer> result = null;

  // private ImageReader imageReader;
  CameraUtil(CraREActivity activity, AutoFitTextureView textureView, ImageView imageView) {
    isprv = true;
//    this.activity = activity;
    this.activityRef = new WeakReference<>(activity);
    this.textureView = textureView;
    this.imageView = imageView;
    mSurfaceTextureListener = new SurfacrTextureListener(this);
    stateCallback = new MStateCallback(this);
  }

  TextureView.SurfaceTextureListener getSurfaceListener() {
    return mSurfaceTextureListener;
  }

  static class SurfacrTextureListener implements TextureView.SurfaceTextureListener {
    private WeakReference<CameraUtil> weakReference;

    public SurfacrTextureListener(CameraUtil cameraUtil) {
      weakReference = new WeakReference<>(cameraUtil);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
      weakReference.get().openCamera(width, height);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
      return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
      CameraUtil cameraUtil = weakReference.get();
      CraREActivity activity = cameraUtil.activityRef.get();
      if (cameraUtil.isprv && cameraUtil.activityRef.get() != null && !activity.isDestroyed()) {
        cameraUtil.isprv = false;
        activity.startPrv();
      }
    }
  }

  static class MStateCallback extends CameraDevice.StateCallback {
    private WeakReference<CameraUtil> weakReference;

    public MStateCallback(CameraUtil cameraUtil) {
      weakReference = new WeakReference<>(cameraUtil);
    }

    @Override
    public void onOpened(@NonNull CameraDevice camera) {
      CameraUtil cameraUtil = weakReference.get();
      cameraUtil.mCameraOpenCloseLock.release();
      cameraUtil.cameraDevice = camera;
      // 开始预览
      cameraUtil.createCameraPreviewSession(); // ②

    }

    @Override
    public void onDisconnected(@NonNull CameraDevice camera) {
      CameraUtil cameraUtil = weakReference.get();
      cameraUtil.mCameraOpenCloseLock.release();
      cameraUtil.cameraDevice.close();
      cameraUtil.cameraDevice = null;
    }

    @Override
    public void onError(@NonNull CameraDevice camera, int error) {
      CameraUtil cameraUtil = weakReference.get();
      cameraUtil.mCameraOpenCloseLock.release();
      cameraUtil.cameraDevice.close();
      cameraUtil.cameraDevice = null;
      if (cameraUtil.activityRef.get() != null && !cameraUtil.activityRef.get().isDestroyed()) {
        cameraUtil.activityRef.get().finish();
      }
    }
  }

  static class CaptureCallBack extends CameraCaptureSession.StateCallback {
    private WeakReference<CameraUtil> weakReference;

    public CaptureCallBack(CameraUtil cameraUtil) {
      weakReference = new WeakReference<>(cameraUtil);
    }

    @Override
    public void onConfigured(@NonNull CameraCaptureSession session) {
      CameraUtil cameraUtil = weakReference.get();
      // 如果摄像头为null，直接结束方法
      if (null == cameraUtil.cameraDevice) {
        return;
      }

      // 当摄像头已经准备好时，开始显示预览
      cameraUtil.captureSession = session;
      try {
        // 设置自动对焦模式
        cameraUtil.previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
            CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
        // 设置自动曝光模式
        cameraUtil.previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
            CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        // cameraUtil.previewRequestBuilder.set(CaptureRequest.CONTROL_AWB_MODE,
        // CaptureRequest.CONTROL_AWB_MODE_AUTO);
        // 开始显示相机预览
        cameraUtil.previewRequest = cameraUtil.previewRequestBuilder.build();
        // 设置预览时连续捕获图像数据
        cameraUtil.captureSession.setRepeatingRequest(cameraUtil.previewRequest, null, null); // ④
      } catch (CameraAccessException e) {
        e.printStackTrace();
      }
      cameraUtil.activityRef.get().onConfigured();

    }

    @Override
    public void onConfigureFailed(@NonNull CameraCaptureSession session) {

    }
  }

  // 打开摄像头
  private void openCamera(int width, int height) {
    CraREActivity activity = activityRef.get();
    if (activity == null) {
      return;
    }
    setUpCameraOutputs(width, height);
    CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);

    try {
      // 打开摄像头
      if (ActivityCompat.checkSelfPermission(activity,
          Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        // ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        // public void onRequestPermissionsResult(int requestCode, String[] permissions,
        // int[] grantResults)
        // to handle the case where the user grants the permission. See the
        // documentation
        // for ActivityCompat#requestPermissions for more details.
        return;
      }
      if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
        throw new RuntimeException("Time out waiting to lock camera opening.");
      }
      if (manager != null) {
        CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraId);
        Range<Integer>[] ranges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
        for (Range<Integer> range : ranges) {
          // 帧率不能太低，大于10
          if (range.getLower() < 10)
            continue;
          if (result == null)
            result = range;
          // FPS下限小于15，弱光时能保证足够曝光时间，提高亮度。range范围跨度越大越好，光源足够时FPS较高，预览更流畅，光源不够时FPS较低，亮度更好。
          else if (range.getLower() <= 15
              && (range.getUpper() - range.getLower()) > (result.getUpper() - result.getLower()))
            result = range;
        }
        // Boolean available =
        // characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
        manager.openCamera(mCameraId, stateCallback, null); // ①
      }

    } catch (CameraAccessException e) {
      e.printStackTrace();
    } catch (InterruptedException e) {
      throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
    }

  }

  /*
   * private void captureStillPicture() { try { if (cameraDevice == null) {
   * return; } // 创建作为拍照的CaptureRequest.Builder final CaptureRequest.Builder
   * captureRequestBuilder
   * =cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); //
   * 将imageReader的surface作为CaptureRequest.Builder的目标
   * captureRequestBuilder.addTarget(imageReader.getSurface()); // 设置自动对焦模式
   * captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
   * CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 设置自动曝光模式
   * captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
   * CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 获取设备方向 int rotation =
   * getWindowManager().getDefaultDisplay().getRotation(); // 根据设备方向计算设置照片的方向
   * captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION ,
   * ORIENTATIONS.get(rotation)); // 停止连续取景 captureSession.stopRepeating(); //
   * 捕获静态图像 captureSession.capture(captureRequestBuilder.build() , new
   * CameraCaptureSession.CaptureCallback() // ⑤ { // 拍照完成时激发该方法
   * 
   * @Override public void onCaptureCompleted(CameraCaptureSession session ,
   * CaptureRequest request, TotalCaptureResult result) { try { // 重设自动对焦模式
   * previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
   * CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); // 设置自动曝光模式
   * previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,CaptureRequest.
   * CONTROL_AE_MODE_ON_AUTO_FLASH); // 打开连续取景模式
   * captureSession.setRepeatingRequest(previewRequest, null, null); } catch
   * (CameraAccessException e) { e.printStackTrace(); } } }, null); } catch
   * (CameraAccessException e) { e.printStackTrace(); } }
   */

  private void createCameraPreviewSession() {
    try {
      SurfaceTexture texture = textureView.getSurfaceTexture();
      texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
      surface = new Surface(texture);
      // 创建作为预览的CaptureRequest.Builder
      // 将TextureView的Surface作为相机的预览显示输出
      previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
      // 将textureView的surface作为CaptureRequest.Builder的目标
      previewRequestBuilder.addTarget(surface);
      // previewRequestBuilder.addTarget(imageReader.getSurface());
      // 创建CameraCaptureSession，该对象负责管理处理预览请求和拍照请求
      // 设置自动曝光帧率范围
      previewRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, result);

      // cameraDevice.createCaptureSession(Arrays.asList(surface,
      // imageReader.getSurface()),new CaptureCallBack(this),null);
      cameraDevice.createCaptureSession(Collections.singletonList(surface), new CaptureCallBack(this), null);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }

  private void setUpCameraOutputs(int width, int height) {
    CraREActivity activity = activityRef.get();
    manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);

    try {
      // 获取指定摄像头的特性
      CameraCharacteristics characteristics = null;
      if (manager != null) {
        characteristics = manager.getCameraCharacteristics(mCameraId);
      }

      // 获取摄像头支持的配置属性
      StreamConfigurationMap map = null;
      if (characteristics != null) {
        map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
      }

      // 获取摄像头支持的最大尺寸
      // 获取摄像头支持的最大尺寸
      Size largest = null;
      if (map != null) {
        largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)), new CompareSizesByArea());
      }

      // 创建一个ImageReader对象，用于获取摄像头的图像数据
      // imageReader = ImageReader.newInstance(width, height,ImageFormat.JPEG, 2);
      // imageReader.setOnImageAvailableListener( new
      // ImageReader.OnImageAvailableListener() {
      // // 当照片数据可用时激发该方法
      // @Override
      // public void onImageAvailable(ImageReader reader) {
      // // 获取捕获的照片数据
      // Image image = reader.acquireNextImage();
      // ByteBuffer buffer = image.getPlanes()[0].getBuffer();
      // byte[] bytes = new byte[buffer.remaining()];
      // buffer.get(bytes);
      // image.close();
      // Log.i("数据","预览");
      // }
      // }, null);

      // 获取最佳的预览尺寸
      if (map == null) {
        return;
      }
      previewSize = getOptimalPreviewSize(map.getOutputSizes(SurfaceTexture.class), width, height);

      previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height, largest);
      // 根据选中的预览尺寸来调整预览组件（TextureView的）的长宽比
      int orientation = activity.getResources().getConfiguration().orientation;
      RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) imageView.getLayoutParams();

      if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
        textureView.setAspectRatio(previewSize.getWidth(), previewSize.getHeight());
        if (width < height * previewSize.getWidth() / previewSize.getHeight()) {
          lp.topMargin = ((width * previewSize.getHeight() / previewSize.getWidth()) - imageView.getHeight()) / 2;
        } else {
          lp.topMargin = (height - imageView.getHeight()) / 2;
        }
      } else {
        textureView.setAspectRatio(previewSize.getHeight(), previewSize.getWidth());
        if (width < height * previewSize.getHeight() / previewSize.getWidth()) {
          lp.topMargin = ((width * previewSize.getWidth() / previewSize.getHeight()) - imageView.getHeight()) / 2;
        } else {
          lp.topMargin = (height - imageView.getHeight()) / 2;
        }
      }
      // imageReader = ImageReader.newInstance(textureView.getWidth(),
      // textureView.getHeight(),ImageFormat.JPEG, 1);
      imageView.setLayoutParams(lp);
      imageView.setVisibility(View.VISIBLE);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    } catch (NullPointerException e) {
      Log.d(TAG, "出现错误");
    }
  }

  private Size getOptimalPreviewSize(Size[] sizes, int w, int h) {
    if (android.os.Build.MODEL.equals("TPS900")) {
      return sizes[0];
    }
    Size optimalSize = null;
    double minDiff = 10;
    double ydbs = (double) h / (double) w;
    for (Size size : sizes) {
      // Log.e("遍历尺寸",size.getWidth()+" "+size.getHeight());
      double ratio = (double) size.getWidth() / (double) size.getHeight();
      if (Math.abs(ratio - ydbs) < minDiff) {
        minDiff = Math.abs(ratio - ydbs);
        optimalSize = size;
      }
    }
    Log.e("尺寸", w + " " + h + " ---" + optimalSize.getWidth() + " " + optimalSize.getHeight());
    return optimalSize;
  }

  public void setTorch(boolean mode) {
    if (cameraDevice == null) {
      return;
    }
    try {
      CaptureRequest.Builder reqBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
      reqBuilder.addTarget(surface);
      reqBuilder.set(CaptureRequest.CONTROL_AE_MODE, CameraMetadata.CONTROL_AE_MODE_ON);
      reqBuilder.set(CaptureRequest.FLASH_MODE, mode ? CameraMetadata.FLASH_MODE_TORCH : CameraMetadata.FLASH_MODE_OFF);
      reqBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, result);
      captureSession.setRepeatingRequest(reqBuilder.build(), null, null);
    } catch (CameraAccessException e) {
      e.printStackTrace();
    }
  }

//  public Bitmap[] getBitmap() {
//    Bitmap[] bitarr = new Bitmap[2];
//    Bitmap rebitmap = textureView.getBitmap();
//    bitarr[0] = rebitmap;
//    if(rebitmap == null) return null;
//    rebitmap = Bitmap.createBitmap(rebitmap, imageView.getLeft(), imageView.getTop(), imageView.getWidth(),
//        imageView.getHeight());
//    bitarr[1] = rebitmap;
//    return bitarr;
//  }
  public Bitmap[] getBitmap() {
    Bitmap[] bitarr = new Bitmap[2];
    try {
      Bitmap rebitmap = textureView.getBitmap();
      if (rebitmap == null) return null;

      bitarr[0] = rebitmap;
      bitarr[1] = Bitmap.createBitmap(rebitmap, imageView.getLeft(), imageView.getTop(),
              imageView.getWidth(), imageView.getHeight());
      return bitarr;
    } finally {
      // 显式回收原始 Bitmap
      if (bitarr[0] != null && !bitarr[0].isRecycled()) {
        bitarr[0].recycle();
      }
    }
  }

  private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
    // 收集摄像头支持的大过预览Surface的分辨率
    List<Size> bigEnough = new ArrayList<>();
    int w = aspectRatio.getWidth();
    int h = aspectRatio.getHeight();
    for (Size option : choices) {
      if (option.getHeight() == option.getWidth() * h / w && option.getWidth() >= width
          && option.getHeight() >= height) {
        bigEnough.add(option);
      }
    }
    // 如果找到多个预览尺寸，获取其中面积最小的
    if (bigEnough.size() > 0) {
      return Collections.min(bigEnough, new CompareSizesByArea());
    } else {
      // 没有合适的预览尺寸
      return choices[0];
    }
  }

  // 为Size定义一个比较器Comparator
  static class CompareSizesByArea implements Comparator<Size> {
    @Override
    public int compare(Size lhs, Size rhs) {
      // 强转为long保证不会发生溢出
      return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
    }
  }

  public void onDestroy() {
    Log.e("相机", "开始关闭");
    try {
      mCameraOpenCloseLock.acquire();
      if (captureSession != null) {
        captureSession.close();
        captureSession = null;
      }
      if (cameraDevice != null) {
        cameraDevice.close();
        cameraDevice = null;
      }
      if (previewRequestBuilder != null) {
        previewRequestBuilder.removeTarget(surface);
        previewRequestBuilder = null;
      }
      if (surface != null) {
        surface.release();
        surface = null;
      }
      if (textureView != null) {
        textureView.setSurfaceTextureListener(null); // 解除监听
        if (textureView.getSurfaceTexture() != null) {
          textureView.getSurfaceTexture().release();
        }
        textureView = null;
      }
      mSurfaceTextureListener = null;
      stateCallback = null;
      activityRef.clear();
      imageView = null;
    } catch (InterruptedException e) {
      throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
    } finally {
      mCameraOpenCloseLock.release();
    }
    Log.e("相机", "已关闭");
  }

}
